package org.dant.ant.extension.net.processors;

import java.util.*;
import java.io.*;


import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;

import org.dant.apache.tools.ant.taskdefs.ExecTask;
import org.dant.ant.extension.utils.StringUtils;
import org.dant.ant.extension.tasks.internal.RemoteResponse;

import org.dant.ant.extension.net.DefaultDispatcher;
import org.dant.ant.extension.net.repository.ProcessItem;
import org.dant.ant.extension.net.repository.ProcessGroup;

public abstract class StartApp extends ExecTask implements Runnable {
  protected String[] args;
  protected String[] envs;

  protected List duplicateProcesses = new ArrayList();

  protected List resultsList = new ArrayList();
  
  protected boolean blocking = false;
  protected boolean unique = false;
  protected int duplicate = 1;
  protected List expectlist = new LinkedList();
  
  protected long start;
  protected long end;

  protected ProcessGroup processGroup;

  public abstract String getProcessKey();

  public void setProcessGroup(ProcessGroup group) {
    this.processGroup = group;
  }

  public ProcessGroup getProcessGroup() {
    return this.processGroup;
  }
  
  public void setExpectedList(List expectlist) {
    this.expectlist = expectlist;
  }

  public void setDuplicate(int duplicate) {
    this.duplicate = duplicate;
  }

  public int getDuplicate() {
    return this.duplicate;
  }

  public void setBlocking(boolean blocking) {
    this.blocking = blocking;
  }

  public boolean getBlocking() {
    return this.blocking;
  }

  public void setUnique(boolean unique) {
    this.unique = unique;
  }

  public boolean getUnique() {
    return this.unique;
  }
  
  public void setArguments(String[] args) {
    this.args = args;
    cmdl.addArguments(args);
  }

  public void setEnvironment(String[] envs) {
    this.envs = envs;
  }
  
  public void checkProcess() {
    if(getUnique())
      DefaultDispatcher.getProcessRepository().checkProcess(getProcessKey());
  }
  
  public void addProcess(Process process, String processID) {
    DefaultDispatcher.getProcessRepository().getProcessDestroyer().add(process);
    addProcess(getProcessKey(), process, processID);
  }

  public void addProcess(String key, Process process, String processID) {
    System.out.println("Push a process <" + StringUtils.hideLongString(key) + "> into the process map");

    ProcessItem pi = new ProcessItem();
    pi.setStartTime(System.currentTimeMillis());
    pi.setTimeOut(timeout.longValue());
    pi.setProcessID(processID);
    pi.add(process);

    pi.setStatus("Running");
    
    processGroup.add(pi);
  }

  public void setup() {
    if(timeout == null || timeout.longValue() <= 0) {
      setTimeout(new Long(1000*60*60*2));  // set timeout to 2 hours
    }
    // Setup a fake project
    this.setProject(new Project());
  }

  private void aggregateResponse(RemoteResponse response) {
    for (Iterator iter=resultsList.iterator();iter.hasNext();) {
      RemoteResponse results = (RemoteResponse) iter.next();
      if (!results.isSuccess()) response.setSuccess(false);
      if (!"N/A".equals(results.getResult()))
          response.appendResult(results.getResult());
      response.appendStdErrBuffer(results.getStdErrBuffer().toString());
      response.appendStdOutBuffer(results.getStdOutBuffer().toString());
      response.setCommandType(results.getCommandType());
    }
    response.setDuplicate(this.duplicate);
    response.setCommand(getProcessKey());
    response.setStartTime(start);
    response.setEndTime(end);

  }

  public void start(RemoteResponse response) {
    setup();
    this.start = System.currentTimeMillis();
    execute();
    this.end = System.currentTimeMillis();
    aggregateResponse(response);
  }

  public void run() {
    super.execute();
  }

  public void execute() throws BuildException {
    System.out.println("Dant daemon is going to start  " + (duplicate) + " processes... ");
    for (int i=0; i<duplicate; i++) {
      Thread execThread = new Thread(this);
      duplicateProcesses.add(execThread);
      execThread.start();
    }
    
    for (Iterator iter=duplicateProcesses.iterator(); iter.hasNext();) {
      try {
        ((Thread)iter.next()).join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
